package recherche;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

import tools.FrenchStemmer;
import tools.FrenchTokenizer;
import tools.Normalizer;

public class Indexation {

	
	/**
	 * Map contenant tous les fichiers a analyser. En clé nous avons un identifiant du fichier et en value un
	 * ArrayList contenant tout le texte du fichier.
	 */
	private HashMap<Integer, ArrayList<String> > mapFichiers = new HashMap<Integer, ArrayList<String>>();

	/**
	 * Fréquence des mots Tokenizer
	 * Map contenant chaque mots en clé et une map en value. 
	 * Cette map contient en key le doc (id) et en value le nb d'occurence dans ce doc.
	 */
	private static HashMap<String, HashMap<Integer, Integer>> dfsTokenizer = new HashMap<String, HashMap<Integer,Integer>>();

	/**
	 * Fréquence des mots Stemmer
	 * Map contenant chaque mots en clé et une map en value. 
	 * Cette map contient en key le doc (id) et en value le nb d'occurence dans ce doc.
	 */
	private static HashMap<String, HashMap<Integer, Integer>> dfsStemmer = new HashMap<String, HashMap<Integer,Integer>>();

	
	/**
	 * Liste des url et titres de documents
	 * Map contenant en clé un identifiant unique pour le document et en value l'url et le titre du fichier correspondant.
	 */
	private static HashMap<Integer,ArrayList<String>> urlTitle ;

	/**
	 * Variable indiquant si nous avons deja extrait les donnees d'index du disque dur.
	 */
	protected static boolean deserialization = false;
	
	/**
	 * Fonction recursive qui va parcourir tous les dossiers du corpus. A chaque fois qu'un fichier sera trouvé, on appelera la 
	 * fonction extractionLignesFichier afin d'en extraire ses informations.
	 * @param dirName
	 * @param norm
	 * @param hits
	 * @throws IOException
	 */
	public void  parserListeFichierRecurs (String dirName) throws IOException {	
		File dir =new File (dirName);
		// Si c'est un fichier non caché
		if (dir.isFile() && !dir.isHidden()){
			//On extrait les lignes du document
			extractionLignesFichier (dirName);
			return;
		}
		// Si c'est un repertoire
		if (dir.isDirectory()) {
			String [] fileNames = dir.list();
			
			for(String fileName : fileNames) {
				String file = dirName + File.separator + fileName;
				parserListeFichierRecurs(file);
			}
		}
	}

	/**
	 * Pour chaque fichier contenu dans mapFichier, cette methode va en extraire les mots par l'appelle à la fonction normalize.
	 * Ensuite nous compterons l'occurence de ces mots pour le fichier courant.
	 * @param normalizer
	 * @param contenuFichier
	 * @param numDoc
	 * @throws IOException
	 */
	private void frequenceMots (Normalizer normalizer, ArrayList<String> contenuFichier, int numDoc, HashMap<String, HashMap<Integer, Integer>> dfs, boolean removeStopWords, boolean doUrl) throws IOException {
		// Appel de la methode de normalisation
		ArrayList<String> URL_Title = new ArrayList<String>();
		ArrayList<String> words = normalizer.normalize_ok(contenuFichier, URL_Title, removeStopWords, doUrl);

		// On indique l'indice de cet article et on l'ajoute à la map titre et url
		getUrlTitle().put(numDoc, URL_Title);
		
		HashMap<Integer, Integer> intTab;
		HashMap<Integer, Integer> mapTmp;

		Integer indiceDoc;

		// Pour chaque mot de la liste, on remplit un dictionnaire
		// du nombre d'occurrences pour ce mot
		for (String word : words) {
			// on recupere le nombre d'occurrences pour ce mot
			intTab = dfs.get(word);
			// Si ce mot n'etait pas encore present dans le dictionnaire,
			// on l'ajoute (case 1 = index de urlTitle, case 2 = nombre d'occurence)
			if (intTab == null) {
				mapTmp = new HashMap<Integer, Integer>();

				mapTmp.put(numDoc, 1);
				dfs.put(word, mapTmp);
			}

			// Sinon, on incrémente le nombre d'occurrence de ce mot
			else {
				indiceDoc = intTab.get(numDoc);
				// Si le document n'est pas referencé, on l'ajoute
				if (indiceDoc == null)		
					intTab.put(numDoc, 1);
				// Sinon on incrémente
				else 
					intTab.put(numDoc, intTab.get(numDoc)+1);
				dfs.put(word, intTab);
			}
		}
	}

	/**
	 * Fonction qui va extraire toutes les lignes d'un fichier dans mapFichiers
	 * @param fileName : Nom du fichier à traiter
	 * @throws IOException
	 */
	private void extractionLignesFichier (String fileName) throws IOException {

		InputStream ips=new FileInputStream(fileName); 
		InputStreamReader ipsr=new InputStreamReader(ips);
		BufferedReader br=new BufferedReader(ipsr);
		String line;
		ArrayList<String> v = new ArrayList<String>();

		// Pour chaque lignes
		while ((line=br.readLine())!=null){
			v.add(line);
		}
		br.close(); 

		// On insere les lignes de ce fichier dans la map
		if (getMapFichiers().size() > 0) 
			getMapFichiers().put(getMapFichiers().size(), v);
		else
			getMapFichiers().put(0, v);

	}

	/**
	 * Methode qui va extraire les mots du contenu de chaque fichier present dans mapFichiers.
	 * @param start
	 * @param end
	 * @param tokenizer
	 * @return
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public void triMapFichiers(Normalizer norm, HashMap<String, HashMap<Integer, Integer>> dfs, boolean removeStopWords, boolean doUrl) throws IOException, InterruptedException {
		// Pour chaque fichier qu'on a recupere en memoire
		for(int i=0; i<getMapFichiers().size(); i++){
			frequenceMots(norm, getMapFichiers().get(i), i, dfs, removeStopWords, doUrl);
			
		}
	}

	/**
	 * Serialisation de l'index
	 */
	public void serializeMap(HashMap<String, HashMap<Integer, Integer>> dfs, String filename) {
		String chaine = "";
		try {
			FileOutputStream fichierIndex = new FileOutputStream(filename);
			
			for (Entry<String, HashMap<Integer, Integer>> freq : dfs.entrySet()){
				chaine = freq.getKey() + " ";
				fichierIndex.write(chaine.getBytes());
				HashMap<Integer, Integer> docs = freq.getValue();
				for (Entry<Integer, Integer> doc : docs.entrySet()){
					chaine = doc.getKey().toString() + "," + doc.getValue().toString() + ";";
					fichierIndex.write(chaine.getBytes());
				}
				fichierIndex.write("\n-\n".getBytes());
			}
			fichierIndex.flush();
			fichierIndex.close();

		}
		catch (java.io.IOException e) {
			e.printStackTrace();
		}
	}
	
	public void serializeURL(){
		String chaineURL;
		FileOutputStream fichierURL;
		try {
			fichierURL = new FileOutputStream("indexURL.ser");
		
		for (Entry<Integer, ArrayList<String>> url : getUrlTitle().entrySet()){
			chaineURL = String.valueOf(url.getKey()) + "===" + url.getValue().get(0)+"===" +
					url.getValue().get(1)+"\n-\n";
			fichierURL.write(chaineURL.getBytes());
		}
		fichierURL.flush();
		fichierURL.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}


	public void deserializeMap(HashMap<String, HashMap<Integer, Integer>> dfs, String filename) {
		try {
			FileInputStream fichierIndex = new FileInputStream(filename);
			InputStreamReader ipsr=new InputStreamReader(fichierIndex);
			BufferedReader br=new BufferedReader(ipsr);
			HashMap<Integer,Integer> map;

			String ligne;
			String[] mots;
			String[] docs;
			String[] doc;
			String key;

			//pour l'index
			while ((ligne=br.readLine())!=null){
				
				if (!ligne.equals("-")){
					mots = ligne.split(" "); //mots[0] = mot , mots[1]=all occ docs
					if (mots != null){
						if (!mots[0].equals("")){
								if (!mots[1].contains(",")){
									mots[0] += mots[1];
									mots[1] = mots[2];
								}
							key = mots[0];
							
							if (mots[1].equals("") && mots[2]!=null)
								mots[1]+=mots[2];
							;
							
							docs = mots[1].split(";");
							
							
							map = new HashMap<Integer, Integer>();
							for (int i=0; i<docs.length; i++){
								doc = docs[i].split(",");

								map.put(Integer.parseInt(doc[0]),Integer.parseInt(doc[1]));

							}
							dfs.put(key, map);
						}
					}
				}
			}
			
		} 
		catch (java.io.IOException e) {
			e.printStackTrace();
		}
	}
	
	public void deserializeURL(){
		FileInputStream fichierURL;
		try {
			fichierURL = new FileInputStream("indexURL.ser");
			String ligne;
			String[] mots;
		
		InputStreamReader ipsrURL=new InputStreamReader(fichierURL);	
		BufferedReader brURL=new BufferedReader(ipsrURL);
		setUrlTitle(new HashMap<Integer, ArrayList<String>>());
		 ArrayList<String> tab;
		 while ((ligne=brURL.readLine())!=null){
			 if (!ligne.equals("-")){
				 mots = ligne.split("==="); //mots[0] = docnum , mots[1]=url, mots[2]=title
				 if (mots != null){
					 tab = new ArrayList<String>();
					 
					 tab.add(mots[1]);
					 if (!mots[2].equals(" ")){
						 tab.add(mots[2]);
					 }
					 else
						 tab.add("_");

					 getUrlTitle().put(Integer.parseInt(mots[0]), tab);
				 }
			 }
			 
		 }
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public HashMap<String, HashMap<Integer, Integer>> getDfsTokenizer() {
		return dfsTokenizer;
	}

	public void setDfsTokenizer(
			HashMap<String, HashMap<Integer, Integer>> dfsTokenizer) {
		this.dfsTokenizer = dfsTokenizer;
	}

	public HashMap<String, HashMap<Integer, Integer>> getDfsStemmer() {
		return dfsStemmer;
	}

	public void setDfsStemmer(HashMap<String, HashMap<Integer, Integer>> dfsStemmer) {
		this.dfsStemmer = dfsStemmer;
	}

	public void setUrlTitle(HashMap<Integer,ArrayList<String>> urlTitle) {
		this.urlTitle = urlTitle;
	}

	public HashMap<Integer,ArrayList<String>> getUrlTitle() {
		return urlTitle;
	}

	public void setMapFichiers(HashMap<Integer, ArrayList<String> > mapFichiers) {
		this.mapFichiers = mapFichiers;
	}

	public HashMap<Integer, ArrayList<String> > getMapFichiers() {
		return mapFichiers;
	}


	
}
